#ifndef KPEXTGP_H
#define KPEXTGP_H

#if defined(_WIN32) || defined(__CYGWIN__)
    #define OS_WIN
#endif
#if defined(__GNUC__) || defined(__GNUG__)
    #define OS_LINUX
#endif

#ifndef KPEXT_BARE_SRC

#ifdef KPEXT_GENLIBDLL
    #if defined(OS_WIN)
        #define KPEXT_LIBDLL __declspec(dllexport)
    #elif defined(OS_LINUX)
        #define KPEXT_LIBDLL __attribute__((visibility("default")))
    #else
        #define KPEXT_LIBDLL
//__declspec(dllexport)
    #endif
#else
    #if defined(OS_WIN)
        #define KPEXT_LIBDLL __declspec(dllimport)
    #elif defined(OS_LINUX)
        #define KPEXT_LIBDLL __attribute__((visibility("default")))
    #else
        #define KPEXT_LIBDLL
//__declspec(dllimport)
    #endif
#endif

#else

#define KPEXT_LIBDLL

#endif




#if defined(__cplusplus)||defined(c_plusplus)
extern "C" {
#endif

#define KPEXT_LIBCALLMODE

/**************************function****************************/

#ifdef OS_WIN
/**
 * @brief 设置windows console 上的控制台虚拟终端序列功能是否打开， 如果打开就支持颜色等text_style
 * @param on  为true 打开
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextSetWinConsoleVT100(bool on);
#endif

/**
 * @brief 设置kp_ext库的log输出为循环文件或默认输出, 如果是文件，那么文件名前缀为 kp_ext_log
 * @param loggername  logger的命名， 如果为nullptr，就会设置使用默认输出
 * @param sizeMB   每个文件最大大小，单位为MB
 * @param filecnt  多少个文件进行循环
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextSetLogger(const char * loggername,
                                                   unsigned int sizeMB,
                                                   unsigned int filecnt
                                                   );


#define KpExtLOG_LEVEL_TRACE 0
#define KpExtLOG_LEVEL_DEBUG 1
#define KpExtLOG_LEVEL_INFO 2
#define KpExtLOG_LEVEL_WARN 3
#define KpExtLOG_LEVEL_ERROR 4
#define KpExtLOG_LEVEL_CRITICAL 5
#define KpExtLOG_LEVEL_OFF 6

/**
 * @brief 设置kp_ext库的log输出日志级别
 * @param level 日志级别，见KpExtLOG_LEVEL
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextSetLoggerLevel(int level);

/**
 * @brief 设置kp_ext库的log输出信息格式化模板
 * @param pattern  格式化模板，参考 https://spdlog.docsforge.com/v1.x/3.custom-formatting/
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextSetLoggerPattern(const char * pattern);

/**
 * @brief 设置是否使能 vulkan 验证层，release版应用时关闭能提高性能
 * @param enable 为true打开验证层
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextSetVKValidationLayerEn(bool enable);

/**
 * @brief 设置要使用的vulkan物理设备作为运算载体
 * @param index  vulkan物理设备号， 小于0表示由json配置文件决定
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextSetVKPhyDeviceIndex(int index);


/**
 * @brief 设置要使用具有哪个pipelineuuid(转换为Hex后字符串)的vulkan物理设备作为运算载体
 * @param puuid  vulkan物理设备的pipelineuuid，注意它是Vulkan的标准里的值转化为大写Hex字符串, 如果为null则使用json配置文件决定
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextSetVKPhyDeviceReqPUUID(const char *puuid);

/**
 * @brief 设置要使用的vulkan物理设备哪些队列家族索引
 * @param indices  队列家族索引数组, 如果为null则清空队列家族索引
 * @param size  队列家族索引数组长度
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextSetVKQueueFamilyIndices(unsigned int * indices, int size);

/**
 * @brief 设置要打开 vulkan 逻辑设备的哪些扩展功能（扩展功能名）
 * @param extensions  扩展功能名char字符串，每个扩展用','分隔， 除了','不能出现其它的无效字符(例如空格)
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextSetVKDeviceReqExtensions(const char * extensions);

/**
 * @brief 设置compute shader 的默认工作组尺寸， 详细参考glsl的compute shader workgroup
 * @param workgroupsize_x  工作组第一维度尺寸
 * @param workgroupsize_y  工作组第二维度尺寸
 * @param workgroupsize_z  工作组第三维度尺寸
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextSetVKComputeShaderDefWGS(unsigned int workgroupsize_x,
                                                                  unsigned int workgroupsize_y,
                                                                  unsigned int workgroupsize_z
                                                                  );


/**
 * @brief 设置图像处理阶段期望使用的线程数量
 * @param stage1TCnt  阶段1期望使用的线程数量
 * @param stage2TCnt  阶段2期望使用的线程数量
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextSetStagesThreadsCount(
        unsigned int stage1TCnt,
        unsigned int stage2TCnt
        );

/**
 * @brief 获取图像处理阶段1  的启用的线程数量
 * @return 启用的线程数量
 */
KPEXT_LIBDLL unsigned int KPEXT_LIBCALLMODE kpextGetStage1ThreadsCount();

/**
 * @brief 获取图像处理阶段2  的启用的线程数量
 * @return 启用的线程数量
 */
KPEXT_LIBDLL unsigned int KPEXT_LIBCALLMODE kpextGetStage2ThreadsCount();


/**
 * @brief kpextInit 初始化kp_ext库， 要使用需要初化后的函数接口，必须先调用些函数，非线程安全
 * @return 成功返回零， 否则返回非零
 */
KPEXT_LIBDLL int KPEXT_LIBCALLMODE kpextInit();


/************************** 图像处理阶段1相关配置函数 ****************************/
/**
 * @brief 配置图像处理阶段1的输入尺寸
 * @param cols  输入列数
 * @param rows  输入行数
 * @param type  输入的类型， 0为16位无符号原始数据， 1为32位浮点数据(求完幅值后的数)
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextCfgStage1Input(int cols, int rows, int type);

/**
 * @brief 配置图像处理阶段1 基于重采样的色散补偿采样索引变形量
 * @param delta 采样索引变形量
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextCfgStage1DCResample(float delta);

/**
 * @brief 配置图像处理阶段1 FFT前开窗操作类型(0:方形 1:汉宁)
 * @param win_type  0:开方形窗 1:开汉宁窗
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextCfgStage1Win(int win_type);

/**
 * @brief 配置图像处理阶段1  FFT后求幅值的参数
 * @param alpha  求幅值log后乘以的倍率
 * @param beta  求幅值log乘以倍率后相加的偏移值
 * @param disable_log  求幅值后是否禁用log运算
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextCfgStage1Amp(float alpha, float beta,
                                                      bool disable_log);

/**
 * @brief 配置图像处理阶段1 求FFT幅值后进行多少帧图像平均
 * @param avg_cnt  平均的帧数
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextCfgStage1Avg(int avg_cnt);

/**
 * @brief 配置图像处理阶段1  图像转置后的ROI剪裁设置
 * @param top  上边剪裁的行数
 * @param left  左边剪裁的列数
 * @param right  右边剪裁的列数
 * @param bottom  下边剪裁的行数
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextCfgStage1ROI(int top,
                                                      int left, int right,
                                                      int bottom);

/**
 * @brief 配置图像处理阶段1  图像ROI操作后是否进行水平翻转设置
 * @param hflip  是否进行水平翻转
 * @param hflip  是否进行垂直平翻转
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextCfgStage1Flip(bool hflip, bool vflip);

/**
 * @brief 配置图像处理阶段1  应用所有配置更改
 * @return 成功返回true, 失败返回false
 */
KPEXT_LIBDLL bool KPEXT_LIBCALLMODE kpextApplyCfgStage1();

/**
 * @brief 获取配置图像处理阶段1 的输出图像尺寸， 应在@ref kpextApplyCfgStage1 后调用
 * @param cols  返回输出列数
 * @param rows  返回输出行数
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextGetStage1OutputSize(int *cols, int *rows);

/**
 * @brief 配置图像处理阶段1 输入输出环形缓冲帧数量（配置小于1张表示不使用环形缓冲）; 应在 @ref kpextStartStage1 前调用;
 * 使用环形缓冲会将 @ref kpextEnqueStage1 的输入暂存到缓冲区,
 * 使用环形缓冲 @ref kpextWaitStage1Output 会返回环形缓冲的内存地址
 * @param framecnt  环形缓冲帧数量
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextCfgStage1RingBufferCnt(int framecnt);

/**
 * @brief 配置图像处理阶段2的指定颜色映射索引查换表数据
 * @param index  配置指定的颜色映射索引
 * @param mapdata  颜色映射查换表数据, 由调用方申请和释放内存，格式为float[len][5]最低维是{input,r,g,b,a},
 *          列如四个映射  {0,0,0,0,255},       //映射源最小值为0
 *                      {100,111,112,113,255},
 *                      {200,221,222,223,255},
 *                      {255,10,11,12,255},    //映射源最大值为255
 * @param len   颜色映射查换表数据长度, 至少要有两组数据，也就是len要大于1
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextCfgStage2CMapLUT(
        unsigned int index,
        const float *mapdata,
        int len
        );


/************************** 依赖于 kpextInit ****************************/

/**
 * @brief kpextRelease  释放kp_ext库, 非线程安全
 * @return  成功返回零， 否则返回非零
 */
KPEXT_LIBDLL int KPEXT_LIBCALLMODE kpextRelease();

/**
 * @brief 启动图像处理阶段1 的所有线程，应在@ref kpextInit之后调用
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextStartStage1();

/**
 * @brief 停止图像处理阶段1 的所有线程，应在@ref kpextInit之后调用
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextStopStage1();

/**
 * @brief 图像处理阶段1  入列一项处理
 * @param in  输入的图像数据内存地址， 由调用方申请和释放
 * @param out  输出的图人数据存放内存地址， 由调用方申请和释放
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextEnqueStage1(void * in, unsigned short * out);

/**
 * @brief 图像处理阶段1  等待处理完一次流程，获取输出内存地址(@ref kpextEnqueStage1 的out地址);
 * 如果获取数据的指针不为空，将输出结果拷贝到获取数据的指针内存
 * @param timeout_ms  超时时长， 单位毫秒
 * @param clonedst   处理完的数据复制到的内存地址，由调用方申请和释放，如查为空不进行复制
 * @return  成功返回内存地址， 失败返回空指针
 */
KPEXT_LIBDLL unsigned short * KPEXT_LIBCALLMODE kpextWaitStage1Output(int timeout_ms, unsigned short * clonedst);

/**
 * @brief 启动图像处理阶段2 的所有线程，应在@ref kpextInit之后调用
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextStartStage2();

/**
 * @brief 停止图像处理阶段2 的所有线程，应在@ref kpextInit之后调用
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextStopStage2();

/**
 * @brief 图像处理阶段2  设置是否进行水平翻转
 * @param enable  是否使能水平翻转
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextSetStage2HFlip(bool enable);

/**
 * @brief 图像处理阶段2  设置是否进行垂直翻转
 * @param enable  是否使能垂直翻转
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextSetStage2VFlip(bool enable);

/**
 * @brief 图像处理阶段2  设置输入图像乘以a前加上的偏移值， 用于调整亮度
 * @param b  输入图像加上偏移值
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextSetStage2Beta(float b);

/**
 * @brief 图像处理阶段2  设置输入图像乘以a， 用于调整亮度
 * @param a  输入图像乘以a
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextSetStage2Mul(float a);

/**
 * @brief 图像处理阶段2  设置输入图像过滤阈值
 * @param thres  阈值
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextSetStage2Threshold(unsigned short thres);

/**
 * @brief 图像处理阶段2  设置输入图像y次幂， 用于调整对比度
 * @param y  输入图像y次幂
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextSetStage2Power(float y);

/**
 * @brief 图像处理阶段2  设置输入图像映射为颜色图像的映射索引
 * @param idx 映射索引
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextSetStage2CMap(unsigned int idx);

/**
 * @brief 图像处理阶段2  入列一项处理， 单通道无符号16位图像转为四通道无符号8位图像
 * @param cols  输入和输出的图像缓冲内存列数
 * @param rows   输入和输出的图像缓冲内存行数
 * @param in  输入的图像数据内存地址， 由调用方申请和释放
 * @param out  输出的图人数据存放内存地址， 由调用方申请和释放
 */
KPEXT_LIBDLL void KPEXT_LIBCALLMODE kpextEnqueStage2(int cols, int rows,
                                                     unsigned short * in,
                                                     unsigned char * out);

/**
 * @brief 图像处理阶段2  等待处理完一次流程，获取输出内存地址(@ref kpextEnqueStage2 的out地址)
 * @param cols  返回输出的图像缓冲内存列数
 * @param rows  返回输出的图像缓冲内存行数
 * @param timeout_ms  超时时长， 单位毫秒
 * @return  成功返回内存地址， 失败返回空指针
 */
KPEXT_LIBDLL unsigned char * KPEXT_LIBCALLMODE kpextWaitStage2Output(int * cols, int *rows,
                                                                     int timeout_ms);

#if defined(__cplusplus)||defined(c_plusplus)
}
#endif

#endif // KPEXTGP_H
